<?php
/**
 * kernel basic function
 * @package kernel
 */

/**
 * 配置
 * @var array
 */
$G_CONFIG=array();

load_lib('/sys/variable');
load_lib('/sys/debugger');
load_lib('/sys/logger');

date_default_timezone_set(get_config('default_timezone'));
//set_exception_handler(get_config('exception_handler'));
//set_error_handler(get_config('error_handler'));
mb_internal_encoding(get_config('charset'));
register_shutdown_function('shutdown');

/**
 * 入口
 */
function main(){
	$objDebugger=sys_debugger::getInstance();
	$objVari=sys_variable::getInstance();
	$objDebugger->startDebug('System');
	$objDebugger->startDebug('Find Controller');
	if(get_config('maintain')){ //系统维护
		$strControllerPath='/error/maintain';
		$mixParam='';
	}else{
		$strURL=$objVari->getParam('DISPATCH_PARAM','server');
		$arrRoute=dispatch($strURL);
		if(empty($arrRoute)){ //常规调度
			$intPos=strrpos($strURL,'/');
			$strControllerPath=substr($strURL,0,$intPos);
			$mixParam=substr($strURL,$intPos);
			if(''==$strControllerPath){
				$strControllerPath='/home/home';
			}else{
				$strControllerPath=strtolower($strControllerPath);
			}
			$mixParam=url_to_param($mixParam);
		}else{ //自定义调度
			$strControllerPath=$arrRoute[0];
			$intCnt=count($arrRoute);
			$mixParam=array();
			for($i=1;$i<$intCnt;++$i){
				$mixParam[]=$arrRoute[$i];
			}
		}
	}
	$objDebugger->stopDebug('Find Controller');
	while(true){
		$objDebugger->showMsg('Target Controller: '.$strControllerPath);
		$objDebugger->startDebug('Get Controller');
		load_controller($strControllerPath);
		$strClassName=path_to_controllername($strControllerPath);
		$arrAllClass=get_declared_classes();
		$bolGetController=false;
		foreach($arrAllClass as $strDeclaredName){
			if($strClassName==$strDeclaredName){
				$bolGetController=true;
				break;
			}
		}
		if(!$bolGetController){
			$strControllerPath='/error/404';
			load_controller($strControllerPath);
			$strClassName=path_to_controllername($strControllerPath);
		}
		$objDebugger->stopDebug('Get Controller');
		$objDebugger->showMsg('Actual Controller: '.$strControllerPath);
		$objDebugger->setDebugController($strControllerPath);
		$objDebugger->startDebug('Handle Controller: '.$strControllerPath);
		$objRelClass=new ReflectionClass($strClassName);
		$objRelInstance=$objRelClass->newInstance();
		$objVari->setURLParam($mixParam);
		$objRelMethod=$objRelClass->getMethod('beforeRequest');
		$objRelMethod->invoke($objRelInstance);
		$objRelMethod=$objRelClass->getMethod('doRequest');
		$mixPage=$objRelMethod->invoke($objRelInstance);
		$objRelMethod=$objRelClass->getMethod('afterRequest');
		$objRelMethod->invoke($objRelInstance);
		$objRelMethod=$objRelClass->getMethod('getDatas');
		$arrParam=$objRelMethod->invoke($objRelInstance);
		$objDebugger->stopDebug('Handle Controller: '.$strControllerPath);
		if($mixPage instanceof sys_controller){
			$strControllerPath=controller_to_path(get_class($mixPage));
		}else{
			$strPagePath=$mixPage;
			break;
		}
	}
	$objDebugger->showMsg('View Page: '.$strPagePath);
	$objDebugger->startDebug('View Page: '.$strPagePath);
	load_page($strPagePath);
	$strClassName=path_to_pagename($strPagePath);
	$objRelClass=new ReflectionClass($strClassName);
	$objRelInstance=$objRelClass->newInstance();
	$objRelMethod=$objRelClass->getMethod('setDatas');
	$objRelMethod->invoke($objRelInstance,$arrParam);
	$objRelMethod=$objRelClass->getMethod('doView');
	$objRelMethod->invoke($objRelInstance);
	$objDebugger->stopDebug('View Page: '.$strPagePath);
}

/**
 * 命令行模式
 */
function main_cmd(){
	$objDebugger=sys_debugger::getInstance();
	$objVari=sys_variable::getInstance();
	$objDebugger->startDebug('System');
	$objDebugger->startDebug('Find Cmd');
	if(get_config('maintain')){ //系统维护
		$strCmdPath='/error/cmdmaintain';
		$mixParam='';
	}else{
		$strCmdParam=$objVari->getParam('DISPATCH_PARAM','server'); //常规调度
		$intPos=strrpos($strCmdParam,'/');
		$strCmdPath=substr($strCmdParam,0,$intPos);
		$mixParam=substr($strCmdParam,$intPos);
		if(''==$strCmdPath){
			$strCmdPath='/home/home';
		}else{
			$strCmdPath=strtolower($strCmdPath);
		}
	}
	$objDebugger->stopDebug('Find Cmd');
	$objDebugger->showMsg('Target Cmd: '.$strCmdPath);
	$objDebugger->startDebug('Get Cmd');
	load_cmd($strCmdPath);
	$strClassName=path_to_controllername($strCmdPath);
	$arrAllClass=get_declared_classes();
	$bolGetController=false;
	foreach($arrAllClass as $strDeclaredClass){
		if($strClassName==$strDeclaredClass){
			$bolGetController=true;
			break;
		}
	}
	if(!$bolGetController){
		$strCmdPath='/error/cmd404';
		load_cmd($strCmdPath);
		$strClassName=path_to_controllername($strCmdPath);
	}
	$objRelClass=new ReflectionClass($strClassName);
	$objRelInstance=$objRelClass->newInstance();
	$objRelMethod=$objRelClass->getMethod('beforeRequest');
	$objRelMethod->invoke($objRelInstance);
	$objRelMethod=$objRelClass->getMethod('doRequest');
	$strPagePath=$objRelMethod->invoke($objRelInstance);
	$objRelMethod=$objRelClass->getMethod('afterRequest');
	$objRelMethod->invoke($objRelInstance);
}

/**
 * 自定义分配路径
 * @param string $p_strURL
 * @return array
 */
function dispatch($p_strURL){
	$arrRouters=get_config('','router');
	$arrMatch=array();
	foreach($arrRouters as $strKey=>$arrRouter){
		foreach($arrRouter as $strPattern){
			if(preg_match($strPattern,$p_strURL,$arrMatch)){
				$arrMatch[0]=$strKey;
				return $arrMatch;
			}
		}
	}
	return $arrMatch;
}

/**
 * 根据Controller名称得到路径
 * @param string $p_strClassName
 * @return string
 */
function controller_to_path($p_strClassName){
	return classname_to_path($p_strClassName,'controller');
}

/**
 * 根据Page名称得到路径
 * @param string $p_strClassName
 * @return string
 */
function pagename_to_path($p_strClassName){
	return classname_to_path($p_strClassName,'page');
}

/**
 * 根据Component名称得到路径
 * @param string $p_strClassName
 * @return string
 */
function component_to_path($p_strClassName){
	return classname_to_path($p_strClassName,'component');
}

/**
 * 根据Class名称得到路径
 * @param string $p_strClassName
 * @param string $p_strClassType
 * @return string
 */
function classname_to_path($p_strClassName,$p_strClassType){
	return '/'.str_replace('_','/',substr($p_strClassName,0,strlen($p_strClassName)-strlen($p_strClassType)));
}

/**
 * 获取某个节点的配置
 * @param string $p_strKey
 * @param string $p_strClass
 * @return string/NULL/array
 */
function get_config($p_strKey='',$p_strClass='common'){
	global $G_CONFIG_PATH,$G_CONFIG;
	if(!isset($G_CONFIG[$p_strClass])){
		foreach($G_CONFIG_PATH as $strPath){
			$strClassFilePath=$strPath.DIRECTORY_SEPARATOR.$p_strClass.'.php';
			if(file_exists($strClassFilePath)){
				include_once $strClassFilePath;
			}
		}
	}
	if(''==$p_strKey){
		if(isset($G_CONFIG[$p_strClass])){
			return $G_CONFIG[$p_strClass];
		}else{
			return array();
		}
	}else{
		if(isset($G_CONFIG[$p_strClass][$p_strKey])){
			sys_variable::getInstance()->addConfigParam($p_strClass,$p_strKey,$G_CONFIG[$p_strClass][$p_strKey]);
			return $G_CONFIG[$p_strClass][$p_strKey];
		}else{
			return NULL;
		}
	}
}

/**
 * 根据URL获取参数
 * @param string $p_strURL
 * @return array
 */
function url_to_param($p_strURL){
	$arrTmp=explode('.',$p_strURL);
	$strExt=array_pop($arrTmp);
	if('html'==$strExt){
		$arrParam=array( 
				'action'=>substr($arrTmp[0],1) 
		);
		$intCnt=count($arrTmp);
		for($i=0;;){
			if(isset($arrTmp[$i+1]) and isset($arrTmp[$i+2])){
				$arrParam[$arrTmp[++$i]]=urldecode($arrTmp[++$i]);
			}else{
				break;
			}
		}
		return $arrParam;
	}elseif('js'==$strExt or 'css'==$strExt){
		return array( 
				$p_strURL 
		);
	}else{
		return array();
	}
}

/**
 * 根据参数得到URL
 * @param string $p_strAction
 * @param array $p_arrParam
 * @return string
 */
function param_to_url($p_strAction,$p_arrParam){
	if(''==$p_strAction){
		return '/';
	}else{
		$strURL='/'.$p_strAction;
		ksort($p_arrParam);
		foreach($p_arrParam as $strKey=>$strValue){
			if(''==$strValue){
				
			}else{
				$strURL.='.'.$strKey.'.'.urlencode($strValue);
			}
		}
		$strURL.='.html';
		return $strURL;
	}
}

/**
 * 合并URL参数
 * @param string $p_strURL
 * @param array $p_arrParam
 * @return string
 */
function merge_url($p_strURL,$p_arrParam){
	$intPosSep=strrpos($p_strURL,'/');
	$strCallURL=substr($p_strURL,0,$intPosSep);
	$strCallParam=substr($p_strURL,$intPosSep);
	$arrParam=url_to_param($strCallParam);
	$strAction=isset($arrParam['action'])?$arrParam['action']:'default';
	unset($arrParam['action']);
	return $strCallURL.param_to_url($strAction, array_merge($arrParam,$p_arrParam));
}

/**
 * 根据路径得到Controller名称
 * @param string $p_strPath
 * @return string
 */
function path_to_controllername($p_strPath){
	return path_to_classname($p_strPath,'controller');
}

/**
 * 根据路径得到Page名称
 * @param string $p_strPath
 * @return string
 */
function path_to_pagename($p_strPath){
	return path_to_classname($p_strPath,'page');
}

/**
 * 根据路径得到Component名称
 * @param string $p_strPath
 * @return string
 */
function path_to_componentname($p_strPath){
	return path_to_classname($p_strPath,'component');
}

/**
 * 根据路径得到Class名称
 * @param string $p_strPath
 * @param string $p_strClassType
 * @return string
 */
function path_to_classname($p_strPath,$p_strClassType){
	return str_replace('/','_',substr($p_strPath,1)).$p_strClassType;
}

/**
 * 加载Component
 * @param string $p_strPath
 */
function load_component($p_strPath){
	load_class($p_strPath,'component');
}

/**
 * 加载Page
 * @param string $p_strPath
 */
function load_page($p_strPath){
	load_class($p_strPath,'page');
}

/**
 * 加载Controller
 * @param string $p_strPath
 */
function load_controller($p_strPath){
	load_class($p_strPath,'controller');
}

/**
 * 加载Controller
 * @param string $p_strPath
 */
function load_cmd($p_strPath){
	load_class($p_strPath,'cmd');
}

/**
 * 加载Lib
 * @param string $p_strPath
 */
function load_lib($p_strPath){
	load_class($p_strPath,'lib');
}

/**
 * 加载Class
 * @param string $p_strPath
 * @param string $p_strClassType
 */
function load_class($p_strPath,$p_strClassType){
	load_file($p_strPath,$p_strClassType,'php');
}

/**
 * 加载文件
 * @param string $p_strPath
 * @param string $p_strPrefix
 * @param string $p_strExtension
 */
function load_file($p_strPath,$p_strPrefix,$p_strExtension){
	global $G_LOAD_PATH;
	foreach($G_LOAD_PATH as $strPath){
		$strClassFilePath=$strPath.DIRECTORY_SEPARATOR.$p_strPrefix.str_replace('/',DIRECTORY_SEPARATOR,$p_strPath).'.'.$p_strExtension;
		if(file_exists($strClassFilePath)){
			include_once $strClassFilePath;
			return;
		}
	}
}

/**
 * 错误捕捉函数
 * @param int $p_intErrNo
 * @param string $p_strErrStr
 * @param string $p_strErrFile
 * @param int $p_intErrLine
 * @param array $p_arrErrContext
 * @return true
 */
function error_handler($p_intErrNo,$p_strErrStr,$p_strErrFile,$p_intErrLine,$p_arrErrContext){
	if(E_STRICT==$p_intErrNo){
		return true;
	}
	$arrLevelName=array( 
			E_ERROR=>'E_ERROR',
			E_WARNING=>'E_WARNING',
			E_PARSE=>'E_PARSE',
			E_NOTICE=>'E_NOTICE',
			E_CORE_ERROR=>'E_CORE_ERROR',
			E_CORE_WARNING=>'E_CORE_WARNING',
			E_COMPILE_ERROR=>'E_COMPILE_ERROR',
			E_COMPILE_WARNING=>'E_COMPILE_WARNING',
			E_USER_ERROR=>'E_USER_ERROR',
			E_USER_WARNING=>'E_USER_WARNING',
			E_USER_NOTICE=>'E_USER_NOTICE',
			E_STRICT=>'E_STRICT' 
	);
	$arrErrInfo=array( 
			'INFO'=>$arrLevelName[$p_intErrNo],
			'MSG'=>$p_strErrStr,
			'FILE'=>$p_strErrFile,
			'LINE'=>$p_intErrLine 
	);
	$arrDebugTrace=debug_backtrace();
	send_trace($arrErrInfo,$arrDebugTrace);
	$arrStopLevel=array( 
			E_ERROR,
			E_WARNING,
			E_CORE_ERROR,
			E_CORE_WARNING,
			E_COMPILE_ERROR,
			E_COMPILE_WARNING,
			E_USER_ERROR,
			E_USER_WARNING 
	);
	if(in_array($p_intErrNo,$arrStopLevel)){
		exit();
	}else{
		return true;
	}
}

/**
 * 异常捕捉函数
 * @param object $p_objException
 * @return true
 */
function exception_handler($p_objException){
	$arrErrInfo=array( 
			'INFO'=>get_class($p_objException),
			'MSG'=>$p_objException->getMessage(),
			'FILE'=>$p_objException->getFile(),
			'LINE'=>$p_objException->getLine() 
	);
	send_trace($arrErrInfo,$p_objException->getTrace());
	exit();
}

/**
 * 生成错误信息
 * @param array $p_arrInfo
 * @param array $p_arrTrace
 */
function send_trace($p_arrInfo,$p_arrTrace){
	$objDebugger=sys_debugger::getInstance();
	if($objDebugger->canDebug()){
		$strDebugHTML='<span style="color:#FF0000;">'.$p_arrInfo['INFO'].'.</span><br />Error file: '.$p_arrInfo['FILE'].'<br />Error line: '.$p_arrInfo['LINE'].'<br />Error message: '.$p_arrInfo['MSG'];
		$objDebugger->showMsg($strDebugHTML,true);
	}else{
		$objLogger=sys_logger::getInstance();
		$arrLogMsg=array( 
				'Info'=>$p_arrInfo['INFO'],
				'Err_File'=>$p_arrInfo['FILE'],
				'Err_Line'=>$p_arrInfo['LINE'],
				'Err_Message'=>$p_arrInfo['MSG'] 
		);
		$objLogger->addLog($arrLogMsg,'errorlog');
	}
}

/**
 * 进程结束时执行函数
 */
function shutdown(){
	$objDebugger=sys_debugger::getInstance();
	if($objDebugger->canDebug()){
		$objDebugger->stopDebug('System');
		$strComponentPath='/sys/debug';
		load_component($strComponentPath);
		$strComponentName=path_to_componentname($strComponentPath);
		$objRelClass=new ReflectionClass($strComponentName);
		$objRelInstance=$objRelClass->newInstance();
		$objRelMethod=$objRelClass->getMethod('doComponent');
		$objRelMethod->invoke($objRelInstance,$strComponentPath);
	}
}